/*
 * ir_print.c
 *
 * Implements logic that prints an intermediate representation
 *
 * Edited by: Jeremy Hansen, RANDY Compton
 */

#include "ir_print.h"



/* ----------------------------------------------------------------------- 
 * Prints out the IR
 * ----------------------------------------------------------------------- 
 */
void ir_print(struct ir_list_t *ir_list)
{
  printf("INTERMEDIATE REPRESENTATION:\n");
  printf("----------------------------\n");
	struct ir_list_t *temp = ir_list;
	while(temp != NULL) {
		printf("ANOTHER FUNCTION:\n");
		struct ir_t *ir = temp->ir;
		while(ir != NULL) {
			ir_print_block(ir);
			ir = ir->next;
		}
		temp = temp->next;
	}
}

/* ----------------------------------------------------------------------- 
 * Prints out a basic block
 * ----------------------------------------------------------------------- 
 */
void ir_print_block(struct ir_t *block) {
	struct tac_t *stmt;
	printf("%s:\n", block->id); // Print block label
	for(stmt = block->statements; stmt != NULL; stmt = stmt->next)
		ir_print_statement(stmt);
	if(block->cond != NULL) // Is it a conditional branch?
		printf("%s\tifnot\t%s\t\n", block->child->id, block->cond);
	else if(block->child == NULL) return;
	else if(block->next != block->child) // Does it need to jump anyway?
		printf("%s\tifnot\t0\t\n", block->child->id);
}

/* ----------------------------------------------------------------------- 
 * Prints out a statement in three-address code
 * ----------------------------------------------------------------------- 
 */
void ir_print_statement(struct tac_t *stmt) {
	if(stmt->v2 != NULL) // Check whether it has a constant
		if(!strcasecmp(stmt->v2, "FALSE"))
			printf("%s\t%s\t0\t%s\n", stmt->v1, instruction(stmt), stmt->v3);
		else if(!strcasecmp(stmt->v2, "TRUE"))
			printf("%s\t%s\t1\t%s\n", stmt->v1, instruction(stmt), stmt->v3);
		else printf("%s\t%s\t%s\t%s\n", stmt->v1, instruction(stmt), stmt->v2,
		 stmt->v3);
	else printf("%s\t%s\t%d\t\n", stmt->v1, instruction(stmt), stmt->n2);
}

/* ----------------------------------------------------------------------- 
 * Determines the name of an instruction
 * ----------------------------------------------------------------------- 
 */
const char *instruction(struct tac_t *stmt) {
	switch(stmt->type) {
		case TAC_END_FUNC: return "end function";
		case TAC_PARAM: return "param";
		case TAC_PRINT: return "print";
		case TAC_NEW: return "new";
		case TAC_FUNC: return "function";
		case TAC_AT: return "at";
		case TAC_ENTER: return "enter";
		case TAC_RETURN: return "return";
		case TAC_SET: return "set";
		case TAC_EQUAL: return "equal";
		case TAC_NOTEQ: return "notequal";
		case TAC_LT: return "lt";
		case TAC_GT: return "gt";
		case TAC_LEQ: return "le";
		case TAC_GEQ: return "ge";
		case TAC_PLUS: return "plus";
		case TAC_MINUS: return "minus";
		case TAC_OR: return "or";
		case TAC_TIMES: return "star";
		case TAC_DIV: return "slash";
		case TAC_MOD: return "mod";
		case TAC_AND: return "and";
		case TAC_NEGATE: return "negate";
		case TAC_NOT: return "not";
		default: return "C is annoying & nearsighted.";
	}
}
